<?php

class Procedure
{
  
  private $profile;
  
  private $participants;
  
  private $tents;
  
  private $default_chapter;
  
  private $first_time;
  
  private $user_id;
  
  private $password;
  
  private $booking;
  
  /**
   * @var sfLogger $logger
   */
  private $logger;

  public function __construct (sfGuardUser $user = null, sfLogger $logger)
  {
//    /$this->logger = $logger;
    
    if (is_null($user) || $user->isNew())
    {
      $this->first_time = true;
      $this->profile = new sfGuardUserProfile();
      $this->participants = new Doctrine_Collection('Participant');
      $this->tents = new Doctrine_Collection('Tent');
    }
    else
    {
      $this->first_time = false;
      $this->profile = $user->getProfile();
      $this->participants = $user->getBooking()->getParticipants();
      $this->tents = $user->getBooking()->getTents();
      sfContext::getInstance()->getLogger()->log(sprintf("Number of tents for user %s retrieved from database upon initalizing procedure: %s", $this->profile->getUser()->getUsername(), count($this->tents)));
    }
  }
  
  /**
   * @return sfLogger
   */
  public function getLogger() {
    //return $this->logger;
    return sfContext::getInstance()->getLogger();
  }
  
  /**
   * @param sfGuardUser $user
   */
  public function setUser (sfGuardUser $user=null) {
    $this->__construct($user);
  }

  /**
   * @return sfGuardUserProfile
   */
  public function getUserProfile ()
  {
    return $this->profile;
  }

  /**
   * @return Doctrine_Collection
   */
  public function getParticipants ()
  {
    return $this->participants;
  }

  /**
   * @return Doctrine_Collection
   */
  public function getTents ()
  {
    return $this->tents;
  }

  public function updateFromAboutMeForm (AboutMeForm $form)
  {
    if (! $form->isBound())
    {
      throw new InvalidArgumentException('Form must be bound.');
    }
    
    $this->profile = $form->getObject();
    $user_participant = new Participant();
    $user_participant->setFirstName($this->profile->getFirstName());
    $user_participant->setLastName($this->profile->getLastName());
    
    $exists = false;
    foreach ($this->participants as $i => $participant)
    {
      if ($participant->getFirstName() == $this->profile->getFirstName() && $participant->getLastName() == $this->profile->getLastName())
      {
        $user_participant = $participant;
        // TODO Is this save enough, determining the participant of the user by names only?
        $exists = $i;
        break;
      }
    
    }
    if ($form->getValue('is_participant') && $exists === false)
    {
      $this->participants->add($user_participant);
    }
    elseif (! $form->getValue('is_participant') && $exists !== false)
    {
      $this->participants->remove($exists);
    }
  }

  public function updateFromDynamicParticipantForm (DynamicParticipantForm $form)
  {
    $this->getLogger()->debug(sprintf('Calling %s', __METHOD__));
    if (! $form->isBound())
    {
      throw new InvalidArgumentException('Form must be bound.');
    }
    
    $price_scaling = PriceScalingTable::getInstance()->getCurrent();
    $this->participants = $form->getParticipants();
    $this->getLogger()->debug(sprintf('%s participants returned by form', count($this->participants)));
    foreach($this->participants as $i => $participant) {
        $this->getLogger()->debug(sprintf('Values of participant %s: %s', $i, print_r($participant->toArray(false), true)));
        $participant->setPriceScaling($price_scaling);
    }
  }

  public function updateFromDynamicTentForm (DynamicTentForm $form)
  {
    if (! $form->isBound())
    {
      throw new InvalidArgumentException('Form must be bound.');
    }
    
    $this->tents = $form->getTents();
  }

  public function getParticipantDefaultValues ()
  {
    return array(
      'chapter' => $this->profile->getChapter());
  }

  public function save ($conn, sfLogger $logger, sfGuardSecurityUser $session_user)
  {
    $this->getLogger()->debug(sprintf('Calling %s', __METHOD__));
    $this->getLogger()->debug(sprintf('Is first time %s', ($this->isFirstTime() ? 'TRUE' : 'FALSE')));

    
    $this->profile = $this->refreshRecord($this->profile);
    // Save user
    if($this->isFirstTime()) {
      $this->getLogger()->debug(sprintf('Saving procedure for user %s for the first time.', $this->profile->getEmailAddress()));
      $pwg = new PasswordGenerator();
      $this->password = $pwg->generate();
      $this->getLogger()->debug(sprintf('Generated new password %s for user %s.', $this->password, $this->profile->getEmailAddress()));
      $user = new sfGuardUser();
      $user->setEmailAddress($this->profile->getEmailAddress());
      $user->setUsername($this->profile->getEmailAddress());
      $user->setPassword($this->password);
      $user->setIsActive(true);
      $user->setIsSuperAdmin(false);
      $user->setProfile($this->profile);
      $user->save($conn);
      $session_user->signIn($user);
      $this->getLogger()->debug(sprintf('Newly created user %s is now signed in.', $this->profile->getEmailAddress()));
    } else {
      $this->getLogger()->debug('Retriving guard user from action');
      $user = $session_user->getGuardUser();//sfGuardUserTable::getInstance()->findOneById($this->user_id);
      $this->getLogger()->debug(sprintf('Retrieved user %s', $user));
      $this->getLogger()->debug('Retrieving profile from user');
      $this->profile = $user->getProfile();
      $this->getLogger()->debug(sprintf('Retrieved user profile %s', $this->profile));
    }
    
    $this->getLogger()->debug(sprintf('Dealing with user %s', $user));
    $this->profile->setUser($user);
    $this->profile->save($conn);
    
    // Save new booking
    if($this->isFirstTime()) {
      $booking = new Booking();
      $this->getLogger()->debug(sprintf('Dealing with new booking'));
    } else {
      $booking = BookingTable::getInstance()->findOneByUserId($user->getId());
      $this->getLogger()->debug(sprintf('Dealing with retrieved booking %s', $booking));
    }
    $booking->setUser($user);
    //$booking->setAmount();
    $booking->save($conn);
    $this->booking = $booking;
    //print_r($booking->toArray());
    // Save participants
    foreach($this->participants as $i => $participant) {
      $this->getLogger()->debug(sprintf('Participant %s', $i));
      $this->getLogger()->debug(sprintf('Values before refresh: %s', print_r($participant->toArray(false), true)));
      $participant = $this->refreshRecord($participant);
      $this->getLogger()->debug(sprintf('Values after refresh: %s', print_r($participant->toArray(false), true)));
      $this->participants->set($i, $participant);
      $participant->setBooking($booking);
      $participant->save();
    }
    //$this->participants->save($conn);
    
    // Save tents
    foreach($this->tents as $i => $tent) {
      $tent = $this->refreshRecord($tent);
      $this->tents->set($i, $tent);
        $tent->setBooking($booking);
    }
    $this->tents->save($conn);
  }
  
  
  /**
   * @return boolean
   */
  public function isFirstTime() {
    return $this->first_time;
  }
  
  private function refreshRecord(sfDoctrineRecord $record) {
    $values = $record->toArray(false);
    $class = get_class($record);
    $record = new $class();
    $record->setArray($values);
    return $record;
  }
  
  public function getBooking() {
    return $this->booking;
  }
  
  public function getPassword() {
    return $this->password;
  }
}